package wiki_playground_dimitar;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathFactoryConfigurationException;
import javax.xml.xpath.XPathFunctionResolver;
import javax.xml.xpath.XPathVariableResolver;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.sun.org.apache.xml.internal.security.transforms.params.XPathContainer;
import com.sun.org.apache.xpath.internal.compiler.XPathDumper;
import com.sun.xml.internal.bind.v2.runtime.output.Encoded;

import processing.core.PApplet;
import processing.core.PFont;
import processing.core.PVector;
//import processing.xml.XMLElement;
import proxml.XMLElement;
import proxml.XMLInOut;
//import proxml.XMLInOut;


public class WikiApi_alemannisch extends PApplet {
	int depth;
	XMLElement xmlE;
	XMLElement xmlE2;
	XMLElement xmlCategoryTree;
	XMLInOut xmlIO;
	
	File isWikiAllTitles;
	FileReader fr;
	String[] lines;
	
	
	

	//String catQueryBase = "http://als.wikipedia.org/w/api.php?action=query&format=xml&list=categorymembers&cmprop=ids|type|title&cmlimit=500&cmtitle=";
	String queryBase = "http://als.wikipedia.org/w/api.php?action=query&format=xml&prop=links&pllimit=500&titles=";
	
	
	int nodeCount;
	Node[] nodes = new Node[100];
	HashMap nodeTable = new HashMap();

	int edgeCount;
	Edge[] edges = new Edge[500];

	static final int nodeColor   = 0xF0C070;
	static final int selectColor = 0xFF3030;
	static final int fixedColor  = 0xFF8080;
	static final int edgeColor   = 0x000000;

	PFont font;

	
	
	public void setup() {
		size(800,800,OPENGL);
		lines = loadStrings("alswiki-20110521-all-titles-in-ns0.txt");
	
		xmlIO = new XMLInOut(this);
		xmlIO.loadElement("als_links_complete_001.xml");
		
		println(edgeCount);
		  font = createFont("SansSerif", 10);
		  textFont(font);  
		  smooth();
		

//		try {
//		XMLOutputFactory myFactory = XMLOutputFactory.newInstance(); 
//			parseStuff();
//		} catch (XPathExpressionException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		} catch (ParserConfigurationException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		} catch (SAXException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		} catch (IOException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		} catch (Exception e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
	}
	
	public void draw() {
		  background(255);
		  translate(width/2,height/2);
		  rotateY(map(mouseX,0,width,0,TWO_PI));
		  rotateX(map(mouseY,0,height,0,TWO_PI));
		  //translate(width/2,height/2);
		  for (int i = 0 ; i < edgeCount ; i++) {
		    edges[i].relax();
		  }
		  for (int i = 0; i < nodeCount; i++) {
		    nodes[i].relax();
		  }
		  for (int i = 0; i < nodeCount; i++) {
		    nodes[i].update();
		  }
		  for (int i = 0 ; i < edgeCount ; i++) {
		    edges[i].draw();
		  }
		  for (int i = 0 ; i < nodeCount ; i++) {
		    nodes[i].draw();
		  }

	}
	
	// Code from Visualizing Data, First Edition, Copyright 2008 Ben Fry.
	// Based on the GraphLayout example by Sun Microsystems.

	void loadData(XMLElement xmle, int depth) {
		  int iterLimit = min(depth,xmle.countChildren());
		  if (depth == 0) iterLimit = xmle.countChildren();
		  System.out.println(xmle.countChildren());
		  for (int i = 0; i < iterLimit; i++) {
			  String fromLabel = xmle.getChild(i).getAttribute("from");
			  for (int j = 0; j < xmle.getChild(i).countChildren(); j++) {
				  String toLabel = xmle.getChild(i).getChild(j).getAttribute("to");
				  addEdge(fromLabel, toLabel);
			  }
		  }
	      //for ()
		
//		  String[] lines = loadStrings("huckfinn.txt");
//		  
//		  // Make the text into a single String object
//		  String line = join(lines, " ");
//		  
//		  // Replace -- with an actual em dash
//		  line = line.replaceAll("--", "\u2014");
//		  
//		  // Split into phrases using any of the provided tokens
//		  String[] phrases = splitTokens(line, ".,;:?!\u2014\"");
//		  //println(phrases);
//
//		  for (int i = 0; i < phrases.length; i++) {
//		    // Make this phrase lowercase
//		    String phrase = phrases[i].toLowerCase();
//		    // Split each phrase into individual words at one or more spaces
//		    String[] words = splitTokens(phrase, " ");
//		    for (int w = 0; w < words.length-1; w++) {
//		      addEdge(words[w], words[w+1]);
//		    }
//		  }
		}


		void addEdge(String fromLabel, String toLabel) {
		  // Filter out unnecessary words
		  if (ignoreWord(fromLabel) || ignoreWord(toLabel)) return;

		  Node from = findNode(fromLabel);
		  Node to = findNode(toLabel);
		  from.increment();
		  to.increment();
		  
		  for (int i = 0; i < edgeCount; i++) {
		    if (edges[i].from == from && edges[i].to == to) {
		      edges[i].increment();
		      return;
		    }
		  } 
		  
		  Edge e = new Edge(from, to);
		  e.increment();
		  if (edgeCount == edges.length) {
		    edges = (Edge[]) expand(edges);
		  }
		  edges[edgeCount++] = e;
		}


		String[] ignore = { "a", "of", "the", "i", "it", "you", "and", "to" };

		boolean ignoreWord(String what) {
		  for (int i = 0; i < ignore.length; i++) {
		    if (what.equals(ignore[i])) {
		      return true;
		    }
		  }
		  return false;
		}


		Node findNode(String label) {
		  label = label.toLowerCase();
		  Node n = (Node) nodeTable.get(label);
		  if (n == null) {
		    return addNode(label);
		  }
		  return n;
		}


		Node addNode(String label) {
		  Node n = new Node(label);  
		  if (nodeCount == nodes.length) {
		    nodes = (Node[]) expand(nodes);
		  }
		  nodeTable.put(label, n);
		  nodes[nodeCount++] = n;  
		  return n;
		}
	
	
	public class Edge {
	  Node from;
	  Node to;
	  float len;
	  int count;


	  Edge(Node from, Node to) {
	    this.from = from;
	    this.to = to;
	    this.len = 50;
	  }
	  
	  
	  void increment() {
	    count++;
	  }
	  
	  
	  void relax() {
	    float vx = to.x - from.x;
	    float vy = to.y - from.y;
	    float d = mag(vx, vy);
	    if (d > 0) {
	      float f = (len - d) / (d * 3);
	      float dx = f * vx;
	      float dy = f * vy;
	      to.dx += dx;
	      to.dy += dy;
	      from.dx -= dx;
	      from.dy -= dy;
	    }
	  }


	  void draw() {
	    stroke(edgeColor,127);
	    strokeWeight(0.35f);
	    //line(from.x, from.y, to.x, to.y);
	    beginShape();
	    vertex(from.x,from.y,from.z);
	    vertex(to.x,to.y,to.z);
	    endShape();
	  }
	}
	
	// Code from Visualizing Data, First Edition, Copyright 2008 Ben Fry.
	// Based on the GraphLayout example by Sun Microsystems.


	class Node {
	  float x, y, z;
	  float dx, dy, dz;
	  PVector pos;
	  float beta, lambda, rho;
	  boolean fixed;
	  String label;
	  int count;


	  Node(String label) {
	    this.label = label;
//	    x = random(width);
//	    y = random(height);
	    beta = random(PI);
	    lambda = random(TWO_PI);
	    rho = random(200);
	    initPos();
	    
	  }
	  
	  void initPos() {
		  pos = new PVector(cos(lambda)*sin(beta)*rho,cos(beta)*rho,sin(lambda)*sin(beta)*rho);
		    x = pos.x;
		    y = pos.y;
		    z = pos.z;
	  }
	  
	  void increment() {
	    count++;
	  }
	  
	  
	  void relax() {
	    float ddx = 0;
	    float ddy = 0;
	    float ddz = 0;

	    for (int j = 0; j < nodeCount; j++) {
	      Node n = nodes[j];
	      if (n != this) {
	        float vx = x - n.x;
	        float vy = y - n.y;
	        float vz = z - n.z;
	        float lensq = vx * vx + vy * vy + vz * vz;
	        if (lensq == 0) {
	          ddx += random(5);
	          ddy += random(5);
	          ddz += random(5);
	        } else if (lensq < 200*100) {
	          ddx += vx / lensq;
	          ddy += vy / lensq;
	          ddz += vz / lensq;
	        }
	      }
	    }
	    float dlen = sqrt(sq(ddx)+ sq(ddy)+sq(ddz)) / 2;
	    if (dlen > 0) {
	      dx += ddx / dlen;
	      dy += ddy / dlen;
	      dz += ddz / dlen;
	    }
	  }


	  void update() {
	    if (!fixed) {      
//	      x += constrain(dx, -5, 5);
//	      y += constrain(dy, -5, 5);
//	      z += constrain(dz, -5, 5);
	      lambda += constrain(dx, -5, 5);
	      rho += constrain(dy, -5, 5);
	      rho += constrain(dz, -5, 5);
	      initPos();
	      x = constrain(x, 0, width);
	      y = constrain(y, 0, height);
	      z = constrain(z, 0, height);
	    }
	    dx /= 2;
	    dy /= 2;
	    dz /= 2;
	  }


	  void draw() {
	    fill(color(nodeColor));
	    stroke(0);
	    strokeWeight(0.5f);
	    
	    //ellipse(x, y, count, count);
	    pushMatrix();
	    translate(x,y,z);
	    ellipse(0, 0, count, count);
	    float w = textWidth(label);

	    if (count > w+2) {
	      fill(0);
	      textAlign(CENTER, CENTER);
	      text(label, x, y);
	    }
	    popMatrix();
	  }
	}

	
	

	
	public void xmlEvent(XMLElement element){
		  //element.printElementTree();
		loadData(element, 100);
		}

	private String toURL(String s) {
		try {
			String s2 = URLEncoder.encode(s, "UTF-8");
			return s2;
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
	}
	
	public void parseStuff() throws ParserConfigurationException, SAXException, 
    IOException, XPathExpressionException, Exception
    
    {
    
      /*create the XML file */  
      XMLOutputFactory myFactory = XMLOutputFactory.newInstance(); 
      XMLStreamWriter writer = myFactory.createXMLStreamWriter(new FileOutputStream("newDoc.xml")); //create document
      writer.writeStartDocument();
      writer.writeCharacters("\n\t");
      writer.writeStartElement("allemanisch_links");  // write <root> element;  
      lines = loadStrings("alswiki-20110521-all-titles-in-ns0.txt");
      int counter = 0;
      for (int i = 1; i < lines.length; i++) {
			String s0 = lines[i];
			xmlE = new XMLElement(this,queryBase+s0);
			try {
				
				int children = xmlE.getChild(0).getChild(1).getChild(0).getChild(0).getChildCount();
				//System.out.println(xmlE.getChild(0).getChild(1).getChild(0).getChild(0).getChild(0).getAttribute("title"));
				//if (children != 0) {
					System.out.println("processing article no. " + (i+1) + " out of " + lines.length + "...");
					writer.writeCharacters("\n\t\t");
					writer.writeStartElement("links");
					writer.writeAttribute("from",lines[i]); //create Attribute; hasn't to be closed
					String c = "" + counter;
					writer.writeAttribute("index",c); //create Attribute; hasn't to be closed
					counter++;
					c = "" + children;
					writer.writeAttribute("total_links",c); //create Attribute; hasn't to be closed
					for (int j = 0 ; j < children; j++) {
						writer.writeCharacters("\n\t\t\t");
						writer.writeStartElement("link");
						writer.writeAttribute("to", xmlE.getChild(0).getChild(1).getChild(0).getChild(0).getChild(j).getAttribute("title")); //create Attribute; hasn't to be closed
						String s = ""+j;
						writer.writeAttribute("index", s);
						writer.writeEndElement();
					}
					writer.writeCharacters("\n\t\t");
					writer.writeEndElement(); //end Attripute-tag; 
					 
					
				//}
				//System.out.println(xmlE.getChild(0).getChild(1).getChild(0).getChild(0).getChild(0).getAttribute("title"));
			} catch (Exception e) {
				// TODO: handle exception
			}
			}
      
      	/*close the XML Document*/ 
		writer.writeCharacters("\n\t");

      	writer.writeEndElement(); //close <root>;
      	writer.writeEndDocument(); 
      	writer.close();
      	System.out.println("file successfull created");
    
            }
	
	public static void main(String _args[]) {
		PApplet.main(new String[] { wiki_playground_dimitar.WikiApi_alemannisch.class.getName() });
	}
	
}
